package org.flown.novel.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.flown.novel.dao.AuthorDAO;
import org.flown.novel.dao.BookDAO;
import org.flown.novel.dao.ChapterDAO;
import org.flown.novel.data.Author;
import org.flown.novel.data.Book;
import org.flown.novel.data.Chapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

@Service
public class BookService
{
    @Autowired
    private AuthorDAO dao_author;
    @Autowired
    private BookDAO dao_book;
    @Autowired
    private ChapterDAO dao_chapter;
    private final QueryWrapper<Book> qw_book = new QueryWrapper<>();
    private final QueryWrapper<Chapter> qw_chapter = new QueryWrapper<>();



    /*Book*/
    public Book getBookByID(int book_id)
    {
        this.qw_book.clear();
        this.qw_book.eq(Book.Column.ID.getName(), book_id);
        return this.dao_book.selectOne(qw_book);
    }


    public Book getBookByName(String name)
    {
        this.qw_book.clear();
        this.qw_book.eq(Book.Column.NAME.getName(), name);
        return this.dao_book.selectOne(qw_book);
    }

    public Book getBookByID(int author_id, int book_id)
    {
        this.qw_book.clear();
        this.qw_book.eq(Book.Column.AUTHOR_ID.getName(), author_id);
        this.qw_book.eq(Book.Column.ID.getName(), book_id);
        return this.dao_book.selectOne(this.qw_book);
    }

    public Book getBookByName(int author_id, String name)
    {
        this.qw_book.clear();
        this.qw_book.eq(Book.Column.AUTHOR_ID.getName(), author_id);
        this.qw_book.eq(Book.Column.NAME.getName(), name);
        return this.dao_book.selectOne(this.qw_book);
    }

    public String getBookDirectory(int book_id)
            throws JsonProcessingException
    {
        this.qw_chapter.clear();
        this.qw_chapter.orderBy(true, true, Chapter.Column.ID.getName());
        this.qw_chapter.eq(Chapter.Column.BOOK_ID.getName(), book_id);
        List<Chapter> list = this.dao_chapter.selectList(this.qw_chapter);
        ObjectMapper mapper = new ObjectMapper();
        ArrayNode directory_root = (ArrayNode) mapper.readTree("[]");
        for (Chapter chapter : list)
        {
            ObjectNode node = directory_root.addObject();
            node.put(Chapter.Column.ID.getName(), chapter.getId());
            node.put(Chapter.Column.BOOK_ID.getName(), chapter.getBookId());
            node.put(Chapter.Column.TITLE.getName(), chapter.getTitle());
            node.put(Chapter.Column.UPLOAD_TIME.getName(), chapter.getUpdateTime().toString());
        }
        return directory_root.toString();
    }


    public boolean hasBook(int book_id) {return this.getBookByID(book_id) != null;}
    public boolean hasBook(String book_name){return this.getBookByName(book_name) != null;}

    /**
     * @return book不存在也会返回false
     * */
    public boolean bookHasChapter(int book_id, int chapter_id)
    {
        Chapter chapter = this.getChapterByID(chapter_id);
        if (chapter == null)
            return false;
        return chapter.getId().equals(book_id);
    }

    /**
     * @return book不存在也会返回false
     * */
    public boolean bookHasChapter(String book_name, int chapter_id)
    {
        Book book = this.getBookByName(book_name);
        if (book == null)
            return false;
        Chapter chapter = this.getChapterByID(chapter_id);
        if (chapter == null)
            return false;
        return chapter.getId().equals(book.getId());
    }

    /**
     * @return author不存在也会返回false
     * */
    public boolean authorHasBook(Author author, int book_id)
    {
        if (author == null)
            return false;
        Book book = this.getBookByID(book_id);
        if (book == null)
            return false;
        return book.getAuthorId().equals(author.getId());
    }

    /**
     * @return author不存在也会返回false
     * */
    public boolean authorHasBook(Author author, String book_name)
    {
        if (author == null)
            return false;
        Book book = this.getBookByName(book_name);
        if (book == null)
            return false;
        return book.getAuthorId().equals(author.getId());
    }
    public boolean authorHasBook(int author_id, int book_id)
    {
        Book book = this.getBookByID(book_id);
        if (book == null)
            return false;
        return book.getAuthorId().equals(author_id);
    }
    public boolean authorHasBook(int author_id, String book_name)
    {
        Book book = this.getBookByName(book_name);
        if (book == null)
            return false;
        return book.getAuthorId().equals(author_id);
    }



    public ServiceResult publishBook(Author author, String name, String synopsis)
    {
        if (name == null || name.equals(""))
            return ServiceResult.NULL_NAME;

        this.qw_book.eq(Book.Column.NAME.getName(), name);
        Book book = this.dao_book.selectOne(this.qw_book);
        if (book != null)
            return ServiceResult.EXISTS_NAME;

        if (this.dao_book.insert(new Book(author.getId(), author.getName(), name, synopsis)) == 0)
            return ServiceResult.FAILED;

        this.qw_book.clear();
        this.qw_book.eq(Book.Column.AUTHOR_ID.getName(), author.getId());
        book = this.dao_book.selectOne(this.qw_book);
        try
        {
            /*修改author的books_id*/
            ObjectMapper mapper = new ObjectMapper();
            ArrayNode node = (ArrayNode) mapper.readTree(author.getBooksId());//异常出处
            node.add(book.getId());
            author.setBooksId(node.toString());
            this.dao_author.updateById(author);//出异常时未运行到这里
            book.createDirectory();//创建存放chapter的目录
            return ServiceResult.SUCCESS;
        }
        catch (JsonProcessingException e)
        {
            this.dao_book.deleteById(book);
            throw new RuntimeException(e);
        }
    }

    public ServiceResult deleteBook(Book book)
    {
        if (this.dao_book.deleteById(book) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }


    public ServiceResult deleteBookByID(int book_id)
    {
        if (this.dao_book.deleteById(this.getBookByID(book_id)) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }

    public ServiceResult deleteBookByName(String book_name)
    {
        if (this.dao_book.deleteById(this.getBookByName(book_name)) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }



    /*Chapter*/
    public Chapter getChapterByID(int chapter_id)
    {
        this.qw_chapter.clear();
        this.qw_chapter.eq(Chapter.Column.ID.getName(), chapter_id);
        return this.dao_chapter.selectOne(this.qw_chapter);
    }


    public String getChapterContentByID(int chapter_id)
    {
        Chapter chapter = this.getChapterByID(chapter_id);
        if (chapter == null)
            return null;
        return chapter.getChapterContent();
    }


    public ServiceResult uploadChapter(int book_id, String title, String content)
    {
        if (title == null || title.equals("")
            || content == null || content.equals(""))
            return ServiceResult.NULL;

        Chapter chapter = new Chapter(book_id, title);
        if (this.dao_chapter.insert(chapter) == 0)
            return ServiceResult.FAILED;

        //获取chapter
        this.qw_chapter.clear();
        this.qw_chapter.last("limit 1");
        this.qw_chapter.orderBy(true, false, Chapter.Column.ID.getName());//倒序查询
        this.qw_chapter.eq(Chapter.Column.BOOK_ID.getName(), book_id);
        this.qw_chapter.eq(Chapter.Column.TITLE.getName(), title);
        chapter = this.dao_chapter.selectOne(this.qw_chapter);
        try
        {
            chapter.setContent(content);//IO异常出于此处

            //更新book chapters_id信息
            this.qw_book.clear();
            this.qw_book.eq(Book.Column.ID.getName(), book_id);
            Book book = this.dao_book.selectOne(this.qw_book);
            book.addChapterID(chapter.getId());
            this.dao_book.updateById(book);//异常时还没运行到这

            return ServiceResult.SUCCESS;
        }
        catch (IOException e)
        {
            chapter.deleteChapterFile();
            this.dao_chapter.deleteById(chapter);
            throw new RuntimeException(e);
        }
    }

    public ServiceResult updateChapterTitle(int chapter_id, String title)
    {
        this.qw_chapter.clear();
        this.qw_chapter.eq(Chapter.Column.ID.getName(), chapter_id);
        Chapter chapter = this.dao_chapter.selectOne(this.qw_chapter);
        chapter.setTitle(title);
        if (this.dao_chapter.updateById(chapter) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }

    public ServiceResult updateChapterContent(int chapter_id, String content)
    {
        this.qw_chapter.clear();
        this.qw_chapter.eq(Chapter.Column.ID.getName(), chapter_id);
        Chapter chapter = this.dao_chapter.selectOne(this.qw_chapter);

        try {
            chapter.setContent(content);
        }
        catch (IOException e) {throw new RuntimeException(e);}

        if (this.dao_chapter.updateById(chapter) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }

    public ServiceResult updateChapter(int chapter_id, String title, String content)
    {
        this.qw_chapter.clear();
        this.qw_chapter.eq(Chapter.Column.ID.getName(), chapter_id);
        Chapter chapter = this.dao_chapter.selectOne(this.qw_chapter);
        chapter.setTitle(title);

        try {
            chapter.setContent(content);
        }
        catch (IOException e) {throw new RuntimeException(e);}

        if (this.dao_chapter.updateById(chapter) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }

    public ServiceResult deleteChapter(int chapter_id)
    {
        this.qw_chapter.clear();
        this.qw_chapter.eq(Chapter.Column.ID.getName(), chapter_id);
        if (this.dao_chapter.delete(this.qw_chapter) == 0)
            return ServiceResult.FAILED;
        return ServiceResult.SUCCESS;
    }

}




